var pd = require('pd'),
    ee = require('eventemitter-light'),
    sax = require('sax'),
    url = require('url'),
    gzip = require('./gzip.js'),
    repeat = require('./repeat.js');
    
var defaults = {
    'connection.host': 'stackexchange.com'
}
    
module.exports = {
    updated: function () {
        return this._lastUpdate;
    },
    request: function () {
        this._client.request(this._connection);
    },
    constructor: function constructor(route, lastUpdate) {
        pd.bindAll(this);
        pd.extend(this, ee, repeat, { constructor: constructor });
        ee.constructor.call(this);
        repeat.constructor.call(this, this.request);
        
        this._client = Object.create(gzip).constructor();
        this._client.on('error', (function () {
            var args = Array.prototype.slice.call(arguments);
            
            args.unshift('error');
            this.emit.apply(this, args);
        }).bind(this));
        this._client.on('complete', parse.bind(this));
        
        var parsed = url.parse(route, true);
        
        if (!parsed.pathname) {
            throw new Error("options.path is invalid");
        }
        
        if (parsed.search) {
            delete parsed.search;
        }
        
        if (!parsed.hostname) {
            parsed.hostname = defaults['connection.host'];
        }
        
        parsed.protocol = 'http:';
        
        this._connection = parsed;
        this._lastUpdate = lastUpdate || 0;
        
        return this;
    }
}

function parse(xml) {
    var feed = sax.parser(true),
        state = {
            tags: [],
            entries: [],
            finished: false,
            latest: 0
        };
        
    feed.onerror = function onerror(e) {
        this.emit('error', e);
    };
    
    feed.onopentag = function onopentag(node) {
        state.tags.push(node.name);
        
        if (node.name === 'entry') {
            state.entries.push({});
        } else if (state.tags[1] === 'entry' && node.name === 'link') {
            state.entries[state.entries.length - 1].link = node.attributes.href;
        }
    };
    
    feed.ontext = (function ontext(text) {
        var tag = state.tags[state.tags.length - 1],
            entry;

        if (state.tags[1] === 'entry') {
            entry = state.entries[state.entries.length - 1];
        
            switch (tag) {
                case 'title':
                    entry.title = text;
                    break;
                case 'name':
                case 'uri':
                    entry.author = entry.author || {};
                    
                    if (tag === 'name') {
                        entry.author.name = text;
                    } else {
                        entry.author.link = text;
                    }
                    
                    break;
                case 'published':
                    entry.posted = +(new Date(text));
                    state.latest = Math.max(entry.posted, state.latest);
                    break;
            }
            
            if (entry.posted && entry.posted < this._lastUpdate) {
                var end = feed.onend;
            
                state.entries.pop();
                
                delete feed.onerror;
                delete feed.onopentag;
                delete feed.ontext;
                delete feed.onclosetag;
                delete feed.onend;
                
                end();
            }
        }
    }).bind(this);
    
    feed.onclosetag = function onclosetag(tag) {
        state.tags.pop();
    }
    
    feed.onend = (function onend() {
        this._lastUpdate = state.latest;
        this.emit('complete', state.entries);
        this.next();
    }).bind(this);
    
    feed.write(xml).close();
}